package com.bigcat.gulimall.demo.mongo.service.impl;


import com.bigcat.gulimall.demo.mongo.entity.Member;
import com.bigcat.gulimall.demo.mongo.repository.MemberRepository;
import com.bigcat.gulimall.demo.mongo.service.MemberService;
import com.bigcat.gulimall.demo.mongo.utils.MongoPageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;


/**
 * 业务层
 *
 * @author sufer_yuan
 * @since 2021-09-24 16:38:43
 */
@Service
public class MemberServiceImpl implements MemberService {
    /**
     * 采用继承MongoRepository，来时先对数据的增删改查操作
     */
    @Autowired
    private MemberRepository memberRepository;

    /**
     * 也可以使用spring-data提供的template来实现对数据的增删改查操作
     */
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void save(Member member) {
        memberRepository.save(member);
    }

    @Override
    public void deleteById(String id) {
        memberRepository.deleteById(id);
        memberRepository.findAll();
    }

    @Override
    public Member findById(String id) {
        //get():如果查询不到值，会报 No value present异常
        //orElse():可以避免get()的情况，当查询不到值时，可以自定义一个对象放回
//        return memberRepository.findById(id).get();
        return memberRepository.findById(id).orElse(new Member());
    }

    /**
     * 获得所有会员
     *
     * @return
     */
    @Override
    public List<Member> findAll() {
        Iterable<Member> iterable = memberRepository.findAll();
        return StreamSupport.stream(iterable.spliterator(), false)
                .collect(Collectors.toList());
    }

    @Override
    public Page<Member> list(Pageable page) {
        return memberRepository.findAll(page);
    }

    /**
     * 获得所有会员，采用mongotemptate方式
     *
     * @return
     */
    public List<Member> templateList() {
        List<Member> members = mongoTemplate.find(
                new Query()
                        .addCriteria(Criteria.where("name").is("zhangsan")),Member.class,"member");
        return members;
    }

    /**
     * Query query = new Query();
     * Criteria criteria =new Criteria();
     * <p>
     * //下面条件相当于select * from order where orderStatus in(16,32) and payStatus=4 and finishTime<=2019-07-05 00:00:00 and (customerId=139 or customerId=1360)
     * criteria.and("orderStatus").in(16, 32).andOperator(Criteria.where("payStatus").is(4)).and("finishTime").lte("2019-07-05 00:00:00")
     * .orOperator(Criteria.where("customerId").is("139"),Criteria.where("customerId").is("1360"));
     * <p>
     * //1360
     * query.addCriteria(criteria);
     * System.out.println(JSON.toJSONString(criteria));
     * long count = mongoTemplate.count(query, ShopMongoOrder.class); //计算总数,用于算法分页数
     * System.out.println(count);
     * <p>
     * <p>
     * int pageNum=1;
     * int pageSize=20;
     * int pageTotal=(int) (count%pageSize==0?count/pageSize:count/pageSize+1); //总页数
     * System.out.println(pageTotal);
     * int offset=(pageNum-1)*pageSize;
     * query.with(Sort.by(Sort.Order.desc("deliveryTime"))); //排序逻辑
     * query.skip(offset).limit(pageSize); // 分页逻辑
     * List<ShopMongoOrder> shopMongoOrders = mongoTemplate.find(query, ShopMongoOrder.class);
     * <p>
     * 分页查询案例
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<Member> pageList(Integer pageNum, Integer pageSize) {
        //创建查询对象
        Query query = new Query();
        //查询条件对象
        Criteria criteria = new Criteria();

//        criteria.and("name").in("kangkang5", "kangkang4").and("age").gt(10).orOperator(Criteria.where("gender").is("boy"));
        //年龄大于18岁和性别为男的会员数据
//        criteria.and("age").gt(18).and("gender").is("boy");
        //相当于：select * from member where age > 16 and (gender = 'boy' or gender = 'girl')
        criteria.and("age").gt(16).orOperator(Criteria.where("gender").is("boy"), Criteria.where("gender").is("girl"));
        //添加查询条件
        query.addCriteria(criteria);

        //获得总记录数
        long count = mongoTemplate.count(query, Member.class);
        //计算页数
//        long pageTotal = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
        long pageTotal = MongoPageUtil.getPageTotal(count, pageSize);
        //计算跳转到的偏移量，如果pageNum小于总页数 那么跳转到(pageNum - 1) * pageSize的位置，
        // 否则跳转到最后一页的起始位置((count % pageSize == 0) ? (count - pageSize) : (count - (count % pageSize)))
//        long offset = pageNum <= pageTotal ? (long) (pageNum - 1) * pageSize : count % pageSize == 0 ? count - pageSize : count - count % pageSize;
        long offset = MongoPageUtil.getOffset(count, pageTotal, pageNum, pageSize);
        //分页
        //db.member.find().skip((pageNum-1)*PageSize).limit(10)
        //db.member.find().skip((2-1)*10).limit(2)
        query.skip(offset).limit(pageSize);
        //排序
        query.with(Sort.by(Sort.Order.desc("age")));

        System.out.println("pageTotal:  " + pageTotal);
        List<Member> members = mongoTemplate.find(query, Member.class);
        return members;
    }

    @Override
    public List<Object> aggQuery() {
        //java的bigDeciaml类型在mongodb中会变成字符串,所以对bigDeciaml进行sum操作,永远都是返回0
        //match是条件:match在group后面就相当于where 语句,在后面相当于having语句,sort要在group后面才有意义
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.group("gender").count().as("total")
                        .sum("age").as("totalAge")
                        .last("name").as("name")

        ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build());
        //如果不加first的时候,取不到orderStatus的值,所以加了后,分组的值才会有数据
        //Aggregation.newAggregationOptions().allowDiskUse(true)是用来解除mongodb 查询数据默认占用最大内存的(默认100M).不然会抛出异常:
        AggregationResults<Object> member = mongoTemplate.aggregate(aggregation, "member", Object.class);
        List<Object> mappedResults = member.getMappedResults();
        return mappedResults;
    }

}

